/**
 * 
 */
package ro.dta.idbi.patterns;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Hashtable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ro.dta.idbi.interfaces.IntegrationOperation;
import ro.dta.idbi.model.AbstractPattern;
import ro.dta.idbi.model.AbstractPrimitivePattern;
import uk.ac.ic.doc.automed.IntegrityException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.SchemaObject;

/**
 * <b>Reverse transformation for the normalisation pattern</b><br />
 * 
 * Example of use:<br />
 * 
 * <code>reverse_normalise_table (&lt;&lt;origTable&gt;&gt;, &lt;&lt;newTable&gt;&gt;, &#123;a1..an&#125;, &#123;b1..bm&#125;)</code>
 * <br />
 * 
 * @author Tudor Dobrila
 * 
 */
public class NormaliseRev extends AbstractPattern {

	private static final Logger LOGGER = Logger.getLogger("ro.dta.idbi.patterns.NormaliseRev");

	/**
	 * Name of the pattern
	 */
	public static final String NAME = "Reverse normalisation";

	/**
	 * Description of the pattern
	 */
	public static final String DESCRIPTION = "Reverse a lossless decomposition";

	/**
	 * Name of the command associated with the pattern
	 */
	public static final String COMMAND = "reverse_normalise_table";

	/**
	 * Integration phase during which the command is applied
	 */
	public static final EnumSet<IntegrationOperation> OPERATION = EnumSet
			.of(IntegrationOperation.CONFORMING);

	/**
	 * Original table (source table)
	 */
	private String origTable;

	/**
	 * Table that will be removed after transformation (target table)
	 */
	private String newTable;

	/**
	 * Determinant set string
	 */
	private String detSetStr;

	/**
	 * Dependent set expressed as a String
	 */
	private String depSetStr;

	/**
	 * Reverse normalisation pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Source schema on which the normalisation will be applied
	 */
	public NormaliseRev(final Schema sourceSchema) throws NotFoundException, IntegrityException {
		super(sourceSchema);

		pattern = Pattern.compile("^" + COMMAND + "[ ]*\\((" + TABLE_REGEX + ")" + COMMA_REGEX
				+ "(" + TABLE_REGEX + ")" + COMMA_REGEX + VAL_SEQ_REGEX + COMMA_REGEX
				+ VAL_SEQ_REGEX + "\\)$");
	}

	/**
	 * Reverse normalisation pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Name of source schema on which the normalisation will be
	 *            applied
	 */
	public NormaliseRev(final String sourceSchema) throws NotFoundException, IntegrityException {
		this(Schema.getSchema(sourceSchema));
	}

	@Override
	protected List<String> getPrimitiveCommands() throws NotFoundException, IntegrityException {
		Hashtable<String, Object[]> colDefs = new Hashtable<String, Object[]>();
		List<String> depCols = splitValues(depSetStr);
		for (String col : depCols) {
			SchemaObject colObj;
			String colName = "<<" + newTable + "," + col + ">>";
			try {
				colObj = sourceSchema.getSchemaObject(colName);
				colDefs.put(col, colObj.getSchemeDefinition());
			} catch (NotFoundException e) {
				throw new IllegalArgumentException("Schema object " + colName + " does not exist.");
			}
		}

		Normalise forward = new Normalise(sourceSchema, origTable, newTable, detSetStr, depSetStr,
				colDefs);
		List<String> commands = forward.getPrimitiveCommands();
		List<String> result = new ArrayList<String>();
		for (String cmd : commands) {
			result.add(0, AbstractPrimitivePattern.getReverseTrans(cmd));
		}

		return result;
	}

	@Override
	protected boolean verify() {
		// TODO Auto-generated method stub
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ro.dta.idbi.model.AbstractPattern#parse(java.lang.String)
	 */
	@Override
	protected void parse(String trans) {
		Matcher matcher = pattern.matcher(trans);
		matcher.find();

		try {
			Normalise forward = new Normalise(sourceSchema);
			forward.parse(matcher);

			origTable = forward.getOrigTable();
			newTable = forward.getNewTable();
			detSetStr = forward.getDeterminantSetString();
			depSetStr = forward.getDependentSetString();
		} catch (NotFoundException e) {
			LOGGER.log(Level.SEVERE, "Fatal exception", e);
		} catch (IntegrityException e) {
			LOGGER.log(Level.SEVERE, "Fatal exception", e);
		}

	}

}
